package com.xy.annotaion.handler.aop.advisor;

import com.xy.annotaion.handler.aop.advice.TestAdvice;
import com.xy.annotaion.handler.aop.advice.adapter.TestAdvisorAdapter;
import com.xy.annotaion.handler.aop.annotation.TestAopLog;
import org.aopalliance.aop.Advice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;

/**
 * firstly , self-defined AdvisorAdapter must be registered,
 * otherelse, it will be handling error;
 * Advisor : default to wrap all function of  all beans.
 * it's so terrible!!!
 * AbstractPointcutAdvisor : OK !!!
 * <p>
 * Bean 'testAdvisor' of type [com.xy.annotaion.handler.aop.advisor.TestAdvisor]
 * is not eligible for getting processed by all BeanPostProcessors
 * (for example: not eligible for auto-proxying)
 * Advisor 被提前 bean processor 提前处理了
 *
 * @author Dell
 */
@Component
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
//public class TestAdvisor implements Advisor {//not OK global intercept all functions
public class TestAdvisor extends AbstractPointcutAdvisor {

    /**
     * register AdvisorAdapter firstly!
     */
    @PostConstruct
    public void init() {
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        registry.registerAdvisorAdapter(new TestAdvisorAdapter());
    }

    @Override
    public Advice getAdvice() {
        return new TestAdvice();
    }

    @Override
    public boolean isPerInstance() {
        return false;
    }

    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {
            @Override
            public ClassFilter getClassFilter() {
                return ClassFilter.TRUE;
            }

            @Override
            public MethodMatcher getMethodMatcher() {
                return new MethodMatcher() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        //this matches be called every aop method called
//                        Pointer.lg("matches1:",targetClass);
//                        Pointer.lg("matches2:",method);
//                        Pointer.lg("matches3:",method.isAnnotationPresent(TestAopLog.class));
                        return method.isAnnotationPresent(TestAopLog.class);
                    }

                    @Override
                    public boolean isRuntime() {
                        return false;
                    }

                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        return false;
                    }
                };
            }
        };
    }
}
